
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ft6336u.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>

#define FT6336U_SCL_PIN 5
#define FT6336U_SDA_PIN 4
#define FT6336U_RST_PIN 8
#define FT6336U_INT_PIN 9

#define I2C_MASTER_TX_BUF_DISABLE 0   /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0   /*!< I2C master doesn't need buffer */
#define ACK_CHECK_EN              0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS             0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL                   0x0 /*!< I2C ack value */
#define NACK_VAL                  0x1 /*!< I2C nack value */

static i2c_port_t i2c_port = I2C_NUM_0;
static bool flag = 0;

int esp32c3_i2c_read(uint8_t reg, uint8_t* bytes, uint32_t len)
{
	int ret = 0;
	i2c_cmd_handle_t cmd;

	cmd = i2c_cmd_link_create();
	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, FT6336U_I2C_7BIT_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN);
	i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);

	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, FT6336U_I2C_7BIT_ADDR << 1 | I2C_MASTER_READ, ACK_CHECK_EN);
	i2c_master_read(cmd, bytes, len - 1, ACK_VAL);
	i2c_master_read_byte(cmd, bytes + len - 1, NACK_VAL);
	i2c_master_stop(cmd);

	ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
	if (ret == ESP_ERR_TIMEOUT) {
		printf("FT6336U Bus is busy\n");
	} else if (ret != ESP_OK) {
		printf("FT6336U Write Failed\n");
	}

	i2c_cmd_link_delete(cmd);

	return ret;
}

int esp32c3_i2c_write(uint8_t reg, uint8_t* bytes, uint32_t len)
{
	int ret = 0;
	i2c_cmd_handle_t cmd;

	cmd = i2c_cmd_link_create();
	i2c_master_start(cmd);
	i2c_master_write_byte(cmd, FT6336U_I2C_7BIT_ADDR << 1 | I2C_MASTER_WRITE, ACK_CHECK_EN);
	i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
	for (int i = 0; i < len; i++) {
		i2c_master_write_byte(cmd, bytes[i], ACK_CHECK_EN);
	}
	i2c_master_stop(cmd);

	ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
	if (ret == ESP_ERR_TIMEOUT) {
		printf("FT6336U Bus is busy\n");
	} else if (ret != ESP_OK) {
		printf("FT6336U Write F+ailed\n");
	}

	i2c_cmd_link_delete(cmd);

	return ret;
}

void esp32c3_rst_pin(int val)
{
	gpio_set_level(FT6336U_RST_PIN, val);
}

void esp32c3_msleep(int ms)
{
	usleep(1000 * ms);
}

static void IRAM_ATTR gpio_isr_handler(void* arg)
{
	flag = 1;
}

void board_init()
{
	int ret = 0;

	/* gpio */
	gpio_reset_pin(FT6336U_RST_PIN);
	gpio_set_direction(FT6336U_RST_PIN, GPIO_MODE_OUTPUT);

	/* interrupt */
	gpio_reset_pin(FT6336U_INT_PIN);
	gpio_set_direction(FT6336U_INT_PIN, GPIO_MODE_INPUT);
	gpio_set_intr_type(FT6336U_INT_PIN, GPIO_INTR_NEGEDGE);
	gpio_install_isr_service(0);
	gpio_isr_handler_add(FT6336U_INT_PIN, gpio_isr_handler, (void*)FT6336U_INT_PIN);

	/* i2c */
	i2c_config_t conf = {
		.mode = I2C_MODE_MASTER,
		.scl_io_num = FT6336U_SCL_PIN,
		.scl_pullup_en = GPIO_PULLUP_ENABLE,
		.sda_io_num = FT6336U_SDA_PIN,
		.sda_pullup_en = GPIO_PULLUP_ENABLE,
		.master.clk_speed = 400000,
	};

	i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
	ret = i2c_param_config(i2c_port, &conf);
	if (ret) {
		printf("err: i2c_param_config(%d, conf), ret = %d\n", i2c_port, ret);
	}
}

void board_deinit()
{
	i2c_driver_delete(i2c_port);
}

void app_main(void)
{
	int ret = 0;
	uint32_t chip = 0;
	uint8_t firmware = 0;
	uint8_t vendor = 0;
	uint16_t version = 0;
	uint8_t num = 0;
	uint16_t x[2] = { 0 };
	uint16_t y[2] = { 0 };
	struct ft6336u tp;

	board_init();

	/* set the param */
	tp.cfg.fix.width = 320;
	tp.cfg.fix.height = 480;

	/* register the operation */
	tp.ops.read = esp32c3_i2c_read;
	tp.ops.write = esp32c3_i2c_write;
	tp.ops.msleep = esp32c3_msleep;
	tp.ops.reset = esp32c3_rst_pin;

	/* ft6336u touch panel api test */
	ret = ft6336u_init(&tp);
	if (ret) {
		printf("err: ft6336u_init(tp), ret = %d\n", ret);
		return;
	}

	ret = ft6336u_get_info(&tp, &chip, &firmware, &vendor, &version);
	if (ret) {
		printf("err: ft6336u_get_info(tp), ret = %d\n", ret);
		return;
	}
	printf("chip     = 0x%08lX\n", chip);
	printf("firmware = 0x%02X\n", firmware);
	printf("vendor   = 0x%02X\n", vendor);
	printf("version  = 0x%04X\n", version);

	while (1) {
		if (flag) {
			flag = 0;
			ret = ft6336u_get_coord(&tp, &num, x, y);
			if (ret) {
				printf("err: ft6336u_get_coord(tp), ret = %d\n", ret);
			} else {
				printf("%d --- (%03d, %03d) --- (%03d, %03d)\n", num, x[0], y[0], x[1], y[1]);
			}
		}

		vTaskDelay(10 / portTICK_PERIOD_MS);
	}

	ft6336u_deinit(&tp);
	board_deinit();
}
